package com.example.validatestudy.demos.jdk8;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.apache.commons.lang.StringUtils;

import java.util.*;
import java.util.function.*;
import java.util.stream.Collectors;

/**
 * @param
 * @version v1
 * @auther: WANGZHENFANG004
 * @summary:
 * @since: 2024 06 04 18 57
 */
public class JdkTest {

    public static void main(String[] args) {

        //lambda表达式本质上是一个匿名方法，由用逗号分隔的参数列表、–>符号、函数体三部分表示
        lamda();

        //Optional
        optional();

        /**
         * 函数式接口  Function  Predicate Consummer Supplier
         * Supplier<T>测试  get()
         * Consumer<T>测试  accept()、andThen()
         * Predicate<T>测试 test()、and()、or()、negate()判断逻辑取非、isEqual()
         * Function<T,R>测试 apply()、compose(Function<? super V, ? extends T> before)先执行befor方法再执行此方法、andThen()、identity() 等于 t—>t
         */
        intf();

        /**
         * 方法引用，有以下几种
         * 构造器引用		Class::new
         * 类名引用静态方法	Class::static_method
         * 对象名引用成员方法	user::method
         * 类名引用成员方法	Class::method
         * super引用父类成员方法	super::method
         * this引用本类成员方法	this::method
         * 数组的构造器引用	int[]::new
         */
        funRef();


        /**
         * stream流操作练习
         */
        stream();


    }

    public static void lamda(){
        List<String> list = Arrays.asList("a","b","c");
        list.forEach((String s)->{
            System.out.println(s);
        });
        list.forEach(s-> System.out.println(s));
        //有返回值
        list.sort((e1,e2)->{
            int result = e1.compareTo(e2);
            return result;
        });
        //只有一个返回值语句, 大括号和return都可以省略.
        list.sort((e1,e2)->e1.compareTo(e2));
        //替换为方法引用
        list.sort(String::compareTo);
    }

    public static void optional(){
        Optional<String> o = Optional.of("a");
        Optional o1 = Optional.empty();
        Optional<String> o2 = Optional.ofNullable(null);

        o.isPresent();
        o.orElse("");
        o.orElseGet(()-> "");
        o.orElseThrow(()->new NullPointerException());
        //如果存在，则执行方法
        o.ifPresent(System.out::println);
        //类型转换
        o.map(item-> {
            User user =new User();
            user.setName(item);
            return user;
        });
        //类型转换，map和flatmap的区别是flatmap的方法返回值是Optional对象，map是直接返回value
        o.flatMap(item -> {
            User user =new User();
            user.setName(item);
            return Optional.of(user);
        });
        Optional<User> op = Optional.of(new User());
        Optional<String> os = op.flatMap(User::getAddress).map(User.Address::getCity);
        System.out.println("flatmap测试");

        //过滤判断
        o.filter(item->item.equals("a"));
        System.out.println("filter返回符合条件的结果"+o.get());

        User o3 = Optional.ofNullable(new User()).orElseThrow(()-> new RuntimeException());
        Optional.ofNullable(new User()).ifPresent(System.out::println);

    }

    /**
     * 函数式接口练习Function  Predicate Consummer Supplier
     */
    public static void intf(){
        People people = new People();
        User user1 = new User("wang");
        people.setUser(user1);
        user1 = people.supTest(()->{
            User user = new User();
            user.setName("测试Supplier");
            return user;
        });
        //Function和Predicate都有返回值，但Predicate没有参数
        String name = people.funTest(user->{
            return user.getName();
        });
        Function<User.Address,String> fun2 = address -> {
            System.out.println(address.getCity());
            return address.getCity();
        };
        Function<User, User.Address> fun1 = user -> {
            System.out.println(user.getAddress().get());
            return user.getAddress().get();
        };
        fun2.compose(fun1).apply(people.user);

        Function<User,User> fun = t->t;
        Function<User,User> function = Function.identity();
        User result = fun.andThen(function).apply(people.user);


        people.conTest(user -> {
            System.out.println(user);
        });

        people.priTest(user->{
            return user.getName().equals("wang");
        });
        //简写
        people.priTest(user->user.getName().equals("wang"));


    }

    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    static class People{
        private User user;
        //Supplier<T>测试   get()
        public User supTest(Supplier<User> supplier){
           return supplier.get();
        }
        //Consumer<T>测试  accept()  andThen()
        public void conTest(Consumer<User> consumer){
            consumer.accept(user);
        }
        //Predicate<T>测试  test()  and() or() negate() isEqual()
        public boolean priTest(Predicate<User> predicate){
            return predicate.test(user);
        }
        //Function<T,R>测试 apply() compose(Function<? super V, ? extends T> before)  andThen()  identity()
        public String funTest(Function<User,String> function){
            return function.apply(user);
        }
    }


    /**
     * 方法引用，有以下几种
     * 构造器引用		Class::new
     * 类名引用静态方法	Class::static_method
     * 对象名引用成员方法	user::method
     * 类名引用成员方法	Class::method
     * 类名引用成员方法注意条件：
     * 当lambda表达式的实现内容有两个相同类型的参数 , 且一个参数对象调用成员方法的参数列表是另外一个参数, 那么可以使用类名引用成员方法来简化代码.
     * super引用父类成员方法	super::method
     * this引用本类成员方法	this::method
     * 数组的构造器引用	int[]::new
     */
    public static void funRef(){
        //构造器引用		Class::new
        User user = getUser("wang",User::new);
        System.out.println("构造器引用测试："+ user.toString());

        //类名引用静态方法	Class::static_method
        sayHello("wang",JdkTest::cnSay);

        //对象名引用成员方法 user::method
        sayHello("《道德经》",user::study);

        /**
         * 类名引用成员方法	Class::method
         * 注意条件：
         * 当lambda表达式的实现内容有两个相同类型的参数 , 且一个参数对象调用成员方法的参数列表是另外一个参数, 那么可以使用类名引用成员方法来简化代码.
         */
        new JdkTest().test();

        //super引用父类成员方法	super::method
        new JdkTest().test1("name");

        //this引用本类成员方法	this::method
        new JdkTest().test2("name");

        //数组的构造器引用	int[]::new
        int[] arr = new JdkTest().test3(1,int[]::new);
        System.out.println(arr);
        
    }

    static User getUser(String name,Function<String,User> function){
        return function.apply(name);
    }

    static void sayHello(String name,Consumer<String> consumer){
        consumer.accept(name);
    }

    static void cnSay(String name){
        System.out.println("你好，"+name);
    }

    public void test() {
        // 方式1: 参数对象进行调用
        boolean b = this.equalsStr("hello", "world",
                (str1, str2) -> !StringUtils.isEmpty(str1) && str1.equals(str2));
        // 方式2: 方法引用-类名::实例方法名
        b = this.equalsStr("hello", "world", String::equals);
        System.out.println(b);
    }

    // 定义一个成员方法, 比较两个字符串是否相等, 第三个参数传递一个BiFunction函数
    private boolean equalsStr(String str1, String str2, BiFunction<String, String, Boolean> fun) {
        return fun.apply(str1, str2);
    }

    void test1(String name){
        sayHello(name,super::equals);
    }
    
    void test2(String name){
        sayHello(name,this::equals);
    }

    private int[] test3(int name, Function<Integer,int[]> function) {
        return function.apply(name);
    }


    /**
     * 流操作练习
     */
    public static void stream(){
        List<User> list = initUserList();
        System.out.println("=====初始集合====\n"+list);

        List<List<String>> strList = list.stream().map(item->item.getHList()).collect(Collectors.toList());
        List<String> nameList = list.stream().map(item->item.getName()).collect(Collectors.toList());
        System.out.println("=====map处理List结果====\n"+strList);
        System.out.println("=====map处理String结果====\n"+nameList);

        List<String> hList = list.stream().flatMap(user -> user.getHList().stream()).collect(Collectors.toList());
        System.out.println("=====flatmap处理List结果====\n"+hList);

        //list.stream().collect(Collectors.groupingBy(User::getSex));
        List<User> filterList = list.parallelStream().filter(item -> item.getId() == 1).collect(Collectors.toList());
        System.out.println("=====filter返回满足条件的结果====\n"+filterList);
        System.out.println("=====初始List结果不变====\n"+list);

        List<Integer> intList = Arrays.asList(1,2,3,4,5,6);
        int sum1 = intList.stream().reduce((x,y)->x+y).get();
        int sum2 = intList.stream().reduce(10,(x,y)->x+y);
        int sum3 = intList.parallelStream().reduce(10,(x,y)->x+y,Integer::sum);
        System.out.println("accumulator累加器的结果："+sum1);
        System.out.println("identiy初始值,accumulator累加器的结果："+sum2);
        System.out.println("identiy初始值,accumulator累加器，combiner组合器的结果："+sum3);

    }

    static List<User> initUserList(){
        ArrayList<User> list = new ArrayList<>();
        User u1 = new User(1, "小蓝", "男", 18);
        User u2 = new User(2, "小黑", "男", 18);
        User u3 = new User(3, "小红", "女", 18);
        u1.setHList(Arrays.asList("篮球","睡觉"));
        u2.setHList(Arrays.asList("羽毛球","睡觉"));
        u3.setHList(Arrays.asList("足球","看电视"));
        list.add(u1);
        list.add(u2);
        list.add(u3);
        return list;
    }
}


@FunctionalInterface
interface UserBuilder{
    User build(String name);
}

@FunctionalInterface
interface Hello{
    void hello(String name);
}


@FunctionalInterface
interface Study<T,R>{

    R toDo(T t);

    default <V> Study<T,V> andThen(Study<R,V> study){
        Objects.requireNonNull(study);
        return (t)-> study.toDo(toDo(t));
    }
}


